#include "main.hpp"

constexpr int target_fps = 15; // 想要的帧率
double fps; // 实际的帧率
int undersample_ratio; // 每隔多少帧取一帧

constexpr int num_of_samples = 512; // 使用多少组数据进行计算
constexpr int num_of_datapoints = 20; // 记录多少组计算的数据
constexpr int compute_interval = 5; // 每记录多少组数据计算一次
constexpr int upload_interval = 9; // 每记录多少组数据上传一次

std::deque<cv::Vec3d> colors; // 存储最近若干组颜色数据，从旧到新
std::deque<double> heartrates; // 存储最近若干组心率数据，从旧到新
std::deque<double> spo2s; // 存储最近若干组血氧饱和度数据，从旧到新
cv::VideoCapture cap(0);

int main() {
    cv::Mat img;
    cap.open(0);
    // 计算采样间隔和真实帧率
    fps = cap.get(cv::CAP_PROP_FPS);
    undersample_ratio = std::round(double(fps)/double(target_fps));
    fps /= undersample_ratio;
    int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);

    create_ui();

    int frame_cnt = 0;
    int sample_cnt = 0;
    while (cv::waitKey(1) != 'q') {
        cap >> img;
        // 为了提高速度，只从连续的若干帧中取一帧进行采样
        if (frame_cnt%undersample_ratio ==0) {
            // 识别人脸，脸的大小不小于视频高度的10/1
            auto face_areas = face_detection(img, cv::Size(height/10, height/10));
            if (face_areas.size() ==0) {
                continue;
            }
            cv::Rect face_area = face_areas[0];
            // 计算出额头的大致区域
            cv::Rect forehead_area(face_area.x + face_area.width/4, face_area.y, face_area.width/2, face_area.height/6);
            // 计算平均颜色
            cv::Vec3b mean_color = area_avg(img, forehead_area);
            // 数据入队
            colors.push_back(mean_color);
            if (colors.size() > num_of_samples) {
                colors.pop_front();
            }
            // 使用多线程执行计算
            if (colors.size()==num_of_samples && sample_cnt%compute_interval==0) {
                std::thread thread_compute(compute);
                thread_compute.detach();
            }
            // 画框标记人脸和额头
            for (auto area: face_areas) {
                cv::rectangle(img, area, cv::Scalar(255, 127, 0));
            }
            cv::rectangle(img, forehead_area, cv::Scalar(255, 0, 127));
            // 显示图像
            show_ui(img, heartrates.begin(), heartrates.end(),spo2s.begin(), spo2s.end());
            ++ sample_cnt;
            std::cout << sample_cnt << std::endl;
        }
        ++frame_cnt;
    }
    cap.release();
    return 0;
}

void compute() {
    static int compute_cnt = 0;
    // 复制数据以避免竞争冒险
    std::vector<cv::Vec3d> colors_copy(colors.begin(), colors.end());
    // 执行计算
    // double heartrate, spo2;
    // std::thread thread_hr(compute_hr<std::vector<cv::Vec3d>::iterator>, heartrate, colors_copy.begin(), colors_copy.end(), fps);
    // std::thread thread_spo2(compute_spo2<std::vector<cv::Vec3d>::iterator>, spo2, colors_copy.begin(), colors_copy.end());
    // thread_hr.join();
    // thread_spo2.join();
    double heartrate = get_heart_rate(colors_copy.begin(), colors_copy.end(), fps);
    double spo2 = get_spo2(colors_copy.begin(), colors_copy.end());
    // 计算结果入队
    heartrates.push_back(heartrate);
    spo2s.push_back(spo2);
    // 数据组数超出记录大小则删除旧的记录
    if (heartrates.size()>num_of_datapoints) {
        heartrates.pop_front();
    }
    if (spo2s.size()>num_of_datapoints) {
        spo2s.pop_front();
    }
    if (compute_cnt%compute_interval == 0) {
        std::string cmd = std::string("at_serial.py ") + std::to_string(heartrate) + std::string(" ") + std::to_string(spo2);
        system(cmd.c_str());
    }
    ++compute_cnt;
}
